#include "../build/release-install-cpp11/include/muduo/net/TcpServer.h"
#include "../build/release-install-cpp11/include/muduo/net/EventLoopThread.h"
#include "../build/release-install-cpp11/include/muduo/net/TcpConnection.h"
#include "../build/release-install-cpp11/include/muduo/net/TcpClient.h"
#include "../build/release-install-cpp11/include/muduo/net/Buffer.h"
#include "../build/release-install-cpp11/include/muduo/net/EventLoop.h"
#include <iostream>
#include <string>

class client
{ // 创建了一个线程，线程里面定义一个epoll对象并且返回指针,定义时epoll对象就开始死循环监听就绪事件
public:
    client(const std::string &sip, uint16_t sport)
        : _client(_loop, muduo::net::InetAddress(sip, sport), "DictClient"), _CDL(1), _loop(_threadloop.startLoop())
    {
        // 设置连接成功时的回调函数--当客户端连接服务端成功时执行该回调函数--构建一个
        //  /TcpConnectionPtr对象传递给回调函数负责IO
        _client.setConnectionCallback([this](const muduo::net::TcpConnectionPtr &conn) -> void
                                      { OnConnection(conn); });
        // 设置客户端fd的就绪事件的回调函数--当客户端fd接收到数据时执行该回调函数
        _client.setMessageCallback([this](const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp T)
                                   { DealMessage(conn, buf, T); });

        // 连接服务端--这个函数不是阻塞的可能没有连接成功就去send数据了
        _client.connect();
        // 程序执行到这里时如果计算器的值没有为0，那么会被加入到条件变量等待唤醒
        _CDL.wait();
    }

    // 给服务发送数据
    bool send(const std::string &msg)
    {
        if (_conn->connected() == false)
        {
            std::cout << "connection break" << std::endl;
            return false;
        }
        _conn->send(msg);
        return true;
    }
    // 连接建立成功时执行，获取一个TcpConnectionPtr对象
    void OnConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        // 判断当前与服务端的连接状态
        if (conn->connected())
        {
            _CDL.countDown(); // 确定连接成功，计数器减到0
            std::cout << "client connect" << std::endl;
            _conn = conn;
        }
        else
        {
            _conn.reset(); // 连接关闭--客户端关闭网络文件fd
            std::cout << "client disconnect" << std::endl;
        }
    }
    // 翻译处理回调函数
    void DealMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp T)
    {
        // 从缓冲区获取用户端发送的数据以字符串对象返回同时清空缓冲区数据
        std::string msg = buf->retrieveAllAsString();
        std::cout << msg << std::endl;
    }

private:
    // /TcpConnectionPtr负责网络套接字的IO处理
    muduo::net::TcpConnectionPtr _conn;
    muduo::net::EventLoopThread _threadloop;
    // 定义一个计数器--里面有加锁和条件变量
    muduo::CountDownLatch _CDL;
    muduo::net::EventLoop *_loop;
    // TcpClient对象只负责创建套接字和建立连接
    // 然后返回一个TcpConnectionPtr对象
    muduo::net::TcpClient _client;
};

int main()
{
    client cli("127.0.0.1", 8080);
    std::string str;
    while (true)
    {
        std::getline(std::cin, str);
        cli.send(str);
    }
}